"""
DPU相关命令封装
"""
import subprocess
import time
from kpautos.engine.case import Case
from kptest.config.enum import DeviceType, HostType, DeviceUtility


class DpuLogic(Case):
    def pre_test_case(self):
        self.device_dut = self.resource.get_device(device_type=DeviceType.Server, utility=DeviceUtility.DUT)
        self.os_host = self.device_dut.get_host(host_type=HostType.HostOS)
        self.bmc_host = self.device_dut.get_host(host_type=HostType.BMC)
        self.device_dpu = self.resource.get_device(device_type=DeviceType.Server, utility=DeviceUtility.DST)
        self.dpu_host = self.device_dpu.get_host(host_type=HostType.HostOS)
        self.dpu_bmc = self.device_dpu.get_host(host_type=HostType.BMC)
        self.dpu_ipmi = self.device_dut.get_api("HKIpmi", api='kptest_extension_api', dispatcher=self.os_host)
        self.dpu_bmc_ip = self.dpu_bmc.local_ip
        self.dpu_bmc_user = self.dpu_bmc.user_name
        self.dpu_bmc_pwd = self.dpu_bmc.password

    def procedure(self):
        pass

    def post_test_case(self):
        pass

    def dpu_optical_module_info(self):
        """
        获取DPU上光模块信息
        :return:
        """
        query_info = self.os_host.run({'command': ['snic_sfp'], 'timeout': 10})
        return query_info

    def query_dpu_sn(self):
        """
        获取DPU SN
        :return:
        """
        sn = self.dpu_host.run({'command': ['dmidecode -s baseboard-serial-number'], 'timeout': 10})[
            "stdout"]
        return sn

    def get_dpu_os_ip(self):
        """
        获取DPU OS IP
        :return:
        """
        return self.dpu_host.local_ip

    def get_dpu_bmc_ip(self):
        """
        获取DPU BMC IP
        :return:
        """
        return self.bmc_host.local_ip

    def snic_sfp_get_optical_module(self):
        """
        获取DPU光模块信息
        :return:
        """
        return self.dpu_host.run({'command': ['snic_sfp'], 'timeout': 10})[
            "stdout"]

    def get_dpu_mc_info(self):
        """
        获取DPU BMC版本信息
        :return:
        """
        params = {"ip": self.dpu_bmc_ip, "user_name": self.dpu_bmc_user, "pwd": self.dpu_bmc_pwd}
        mc_info = self.dpu_ipmi.get_mc_info(params=params)
        return mc_info

    def get_dpu_fru_info(self):
        """
        获取DPU BMC版本信息
        :return:
        """
        params = {"ip": self.dpu_bmc_ip, "user_name": self.dpu_bmc_user, "pwd": self.dpu_bmc_pwd}
        mc_info = self.dpu_ipmi.get_fru_info(params=params)
        return mc_info

    def get_dpu_sdr_info(self):
        """
        获取DPU BMC版本信息
        :return:
        """
        params = {"ip": self.dpu_bmc_ip, "user_name": self.dpu_bmc_user, "pwd": self.dpu_bmc_pwd}
        mc_info = self.dpu_ipmi.get_sdr_info(params=params)
        return mc_info

    def ping_until_reachable(host_ip=None, timeout=600, interval=2):
        """
        持续ping一个IP直到ping通或超时

        参数:
            ip: 要ping的IP地址
            timeout: 总超时时间(秒)，默认60秒
            interval: 每次ping的间隔时间(秒)，默认2秒

        返回:
            True: ping通
        抛出:
            TimeoutError: 超时未ping通
        """
        start_time = time.time()

        while time.time() - start_time < timeout:
            try:
                # Windows系统使用'-n'参数，Linux使用'-c'
                result = subprocess.run(['ping', '-n', '1', host_ip],
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE,
                                        timeout=interval)

                # 返回码为0表示ping成功
                if result.returncode == 0:
                    return True

            except subprocess.TimeoutExpired:
                pass

            time.sleep(interval)

        raise TimeoutError(f"Ping {host_ip} timed out after {timeout} seconds")

    def ping_not_reachable(self, ip, timeout=120, interval=2):
        """
        检测服务器是否复位(从可ping通变为不可ping通)

        参数:
            ip: 要检测的服务器IP
            timeout: 总检测超时时间(秒)
            interval: 检测间隔时间(秒)

        返回:
            True: 检测到服务器复位(从可ping通变为不可ping通)
            False: 超时未检测到复位
        """
        import subprocess
        import time

        start_time = time.time()
        was_reachable = False

        try:
            subprocess.run(['ping', '-n', '1', ip],
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE,
                           check=True,
                           timeout=interval)
            was_reachable = True
        except:
            raise RuntimeError(f"服务器 {ip} 初始状态不可达，无法检测复位")

        # 持续检测直到服务器变为不可ping通或超时
        while time.time() - start_time < timeout:
            try:
                subprocess.run(['ping', '-n', '1', ip],
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE,
                               check=True,
                               timeout=interval)
            except:
                # 从可ping通变为不可ping通，说明服务器正在复位
                if was_reachable:
                    return True
                else:
                    continue

            time.sleep(interval)

        return False

    def set_dpu_power(self, status="reset"):
        """
        ipmi 带外设置值dpu电源状态
        :return:
        """
        params = {"ip": self.dpu_bmc_ip, "user_name": self.dpu_bmc_user, "pwd": self.dpu_bmc_pwd}
        restult = self.dpu_ipmi.set_dpu_power_status(params=params)
        if "Chassis Power Control" in restult[0]:
            return True
        raise Exception("设置 DPU电源状态失败")

    def set_dpu_boot_flag(self, boot_flag="none"):
        """
        ipmi 带外设置值dpu启动项
        :return:
        """
        params = {"ip": self.dpu_bmc_ip, "user_name": self.dpu_bmc_user, "pwd": self.dpu_bmc_pwd}
        self.dpu_ipmi.set_dpu_boot_dev(params=params)

    def get_dpu_boot_flag(self):
        """
        ipmi 带外设置值dpu启动项
        :return:
        """
        params = {"ip": self.dpu_bmc_ip, "user_name": self.dpu_bmc_user, "pwd": self.dpu_bmc_pwd}
        self.dpu_ipmi.get_dpu_boot_dev(params=params)
